/*
 * Reksio - Memory Map Editor
 * Copyright (C) 2023 CERN
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * In applying this licence, CERN does not waive the privileges and immunities
 * granted to it by virtue of its status as an Intergovernmental Organization or
 * submit itself to any jurisdiction.
 */

#include "consolestream.h"
#include "mainwindow.h"

#include <QKeyEvent>

ConsoleStream::ConsoleStream(std::ostream &stream/*, QTextEdit *text_edit*/):
    std::basic_streambuf<char> (),
    _stream(stream),
    _old_buf(_stream.rdbuf()),
    _console(MainWindow::console)
{
    stream.rdbuf(this);
}

ConsoleStream::~ConsoleStream()
{
    _stream.rdbuf(_old_buf);
    qInstallMessageHandler(nullptr);
}

void ConsoleStream::registerMyConsoleMessageHandler()
{
    qInstallMessageHandler(myConsoleMessageHandler);
}

void ConsoleStream::myConsoleMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
	static_cast<void>(context); // suppress -Wunused-parameter

    // filter out some shit
    if(msg.startsWith("QWindowsWindow::setGeometry") ||
            msg.startsWith("QCoreApplication::postEvent") ||
            msg.startsWith("QXcbConnection") ||
            msg.startsWith("Case insensitive sorting") ||
            msg.startsWith("Numeric mode unsupported") ||
            msg.startsWith("libpng warning: iCCP:")
            )
        return;
    QTextEdit* console = MainWindow::console;
    QByteArray localMsg = msg.toLocal8Bit();
    QString message;
    QString color;
    QTextCharFormat format;

    switch(type)
    {
    case QtDebugMsg:
        color = "black";
        message = QObject::tr("Debug: %1").arg(localMsg.constData());
        break;
    case QtInfoMsg:
        color = "black";
        message = QObject::tr("Info: %1").arg(localMsg.constData());
        break;
    case QtWarningMsg:
        color = "blue";
        message = QObject::tr("Warning: %1").arg(localMsg.constData());
        format.setFontWeight(QFont::DemiBold);
        break;
    case QtCriticalMsg:
        color = "red";
        message = QObject::tr("Critical: %1").arg(localMsg.constData());
        format.setFontWeight(QFont::DemiBold);
        break;
    case QtFatalMsg:
        color = "red";
        message = QObject::tr("Fatal: %1").arg(localMsg.constData());
        format.setFontWeight(QFont::DemiBold);
        break;
    }

    //message = QObject::tr("%1 (%2:%3, %4)").arg(message).arg(context.file).arg(context.line).arg(context.function);

    message = QTime::currentTime().toString("hh:mm:ss") + ": " + message;

    console->moveCursor(QTextCursor::End);

    QTextCursor cursor(console->textCursor());
    format.setForeground(QBrush(QColor(color)));
    cursor.setCharFormat(format);

    cursor.insertText(message + '\n');
    console->ensureCursorVisible();
}

std::basic_streambuf<char>::int_type ConsoleStream::overflow(std::basic_streambuf<char>::int_type v)
{
    if (v != traits_type::eof() && _console) {
        _console->moveCursor(QTextCursor::End);
        _console->setTextColor(Qt::black);
        _console->insertPlainText((QChar(v)));
        _console->ensureCursorVisible();
        return v;
    }
    return traits_type::eof();
}

std::streamsize ConsoleStream::xsputn(const char *p, std::streamsize n)
{
    if(_console && n > 0)
    {
        _console->moveCursor(QTextCursor::End);
        _console->setTextColor(Qt::black);
        _console->insertPlainText(QString::fromLatin1(p, static_cast<int>(n)));
        _console->ensureCursorVisible();
    }
    return n;
}
